Skip to content

HDDS-14036. StreamRead: Make preReadSize, responseDataSize and read timeout configurable#9461

Merged
szetszwo merged 11 commits intoapache:masterfrom
Russole:HDDS-14036
Dec 15, 2025
Merged

HDDS-14036. StreamRead: Make preReadSize, responseDataSize and read timeout configurable#9461
szetszwo merged 11 commits intoapache:masterfrom
Russole:HDDS-14036

Conversation

@Russole
Copy link
Copy Markdown
Contributor

@Russole Russole commented Dec 8, 2025

What changes were proposed in this pull request?

This change makes the fixed values used by StreamBlockInputStream for
preReadSize, responseDataSize, and the streaming read timeout configurable
via OzoneClientConfig and ozone-default.xml.
This allows users and operators to tune stream-read performance based on workload
characteristics and cluster latency.

Currently, StreamBlockInputStream uses the following fixed values:

  • preReadSize = 32MB
  • responseDataSize = 1MB
  • a fixed 10-second streaming read timeout (poll(10, TimeUnit.SECONDS))

These defaults work for general cases but may not be optimal for all environments, particularly under higher latency conditions or workloads that benefit from larger streaming buffers or more fine-grained timeout control.

This PR introduces three new client-side configuration keys to make these parameters fully configurable:

  • ozone.client.stream.read.pre-read-size
  • ozone.client.stream.read.response-data-size
  • ozone.client.stream.read.timeout

Changes include:

  • Adding the new configuration keys and default values to ozone-default.xml.
  • Introducing corresponding fields and getters in OzoneClientConfig.
  • Updating StreamBlockInputStream to use values from OzoneClientConfig instead of fixed constants.
  • Replacing the previous fixed 10-second timeout in StreamingReader.poll() with a configurable timeout.
  • Adding constants to OzoneConfigKeys for consistency and discoverability.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-14036

How was this patch tested?

GitHub Actions CI for my fork ran successfully with all checks passing.


ByteBuffer readFromQueue() throws IOException {
final ReadBlockResponseProto readBlock = poll(10, TimeUnit.SECONDS);
final ReadBlockResponseProto readBlock = poll(readTimeoutMs, TimeUnit.SECONDS);
Copy link
Copy Markdown
Contributor

@sreejasahithi sreejasahithi Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Russole for working on this, left few comments

Because readTimeoutMs is in milliseconds, you must pass TimeUnit.MILLISECONDS so the timeout isn’t misinterpreted as seconds

Suggested change
final ReadBlockResponseProto readBlock = poll(readTimeoutMs, TimeUnit.SECONDS);
final ReadBlockResponseProto readBlock = poll(readTimeoutMs, TimeUnit.MILLISECONDS);

private int streamReadResponseDataSize = 1 << 20;

@Config(key = "ozone.client.stream.read.timeout",
defaultValue = "1000",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value should be 10000 in order to match with the ozone-default.xml

Copy link
Copy Markdown
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Russole for working on this.

Please don't also add the config to OzoneConfigKeys and ozone-default.xml.

Please add test cases to verify custom config is applied.

Comment on lines +299 to +300
defaultValue = "1000",
type = ConfigType.INT,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use ConfigType.TIME and "10s".

type = ConfigType.INT,
tags = {ConfigTag.CLIENT},
description = "Timeout in ms for receiving streaming read responses.")
private int streamReadTimeoutMs = 10_000;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plese use Duration instead of int and drop Ms from name.

Comment on lines +585 to +586
public int getStreamReadTimeoutMs() {
return streamReadTimeoutMs;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return Duration and drop Ms from name.

@jojochuang
Copy link
Copy Markdown
Contributor

@yandrey321

@Russole
Copy link
Copy Markdown
Contributor Author

Russole commented Dec 10, 2025

Many thanks to @adoroszlai, @sreejasahithi, and @jojochuang for the reviews. I've addressed the comments — please let me know if any further changes are needed.

@adoroszlai adoroszlai changed the title Hdds 14036. StreamRead: Make preReadSize, responseDataSize and read timeout configurable HDDS-14036. StreamRead: Make preReadSize, responseDataSize and read timeout configurable Dec 10, 2025
Copy link
Copy Markdown
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Russole for updating the patch.

Comment on lines +697 to +717
public static final String
OZONE_CLIENT_STREAM_READ_PRE_READ_SIZE =
"ozone.client.stream.read.pre-read-size";
public static final long
OZONE_CLIENT_STREAM_READ_PRE_READ_SIZE_DEFAULT =
32L << 20;

public static final String
OZONE_CLIENT_STREAM_READ_RESPONSE_DATA_SIZE =
"ozone.client.stream.read.response-data-size";
public static final int
OZONE_CLIENT_STREAM_READ_RESPONSE_DATA_SIZE_DEFAULT =
1 << 20;

public static final String
OZONE_CLIENT_STREAM_READ_TIMEOUT =
"ozone.client.stream.read.timeout";
public static final int
OZONE_CLIENT_STREAM_READ_TIMEOUT_DEFAULT =
10_000;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, if my original comment was confusing. Please remove these, too.

Suggested change
public static final String
OZONE_CLIENT_STREAM_READ_PRE_READ_SIZE =
"ozone.client.stream.read.pre-read-size";
public static final long
OZONE_CLIENT_STREAM_READ_PRE_READ_SIZE_DEFAULT =
32L << 20;
public static final String
OZONE_CLIENT_STREAM_READ_RESPONSE_DATA_SIZE =
"ozone.client.stream.read.response-data-size";
public static final int
OZONE_CLIENT_STREAM_READ_RESPONSE_DATA_SIZE_DEFAULT =
1 << 20;
public static final String
OZONE_CLIENT_STREAM_READ_TIMEOUT =
"ozone.client.stream.read.timeout";
public static final int
OZONE_CLIENT_STREAM_READ_TIMEOUT_DEFAULT =
10_000;


Token<OzoneBlockTokenIdentifier> token = null;
// Mock XceiverClientFactory since StreamBlockInputStream requires it in the constructor
XceiverClientFactory xceiverClientFactory = Mockito.mock(XceiverClientFactory.class);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please add import static org.mockito.Mockito.mock;

Comment on lines +297 to +301
conf.set("ozone.client.stream.read.pre-read-size", "67108864");
conf.set("ozone.client.stream.read.response-data-size", "2097152");
conf.set("ozone.client.stream.read.timeout", "5s");

OzoneClientConfig clientConfig = conf.getObject(OzoneClientConfig.class);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OzoneConfiguration is not required, please create OzoneClientConfig directly and set values using its methods.

    OzoneClientConfig clientConfig = new OzoneClientConfig();
    clientConfig.set...(...);

}

@Test
public void testCustomStreamReadConfigIsApplied() throws Exception {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a unit test, since it does not require a working cluster. Please move to new test class hadoop-hdds/client/src/test/java/org/apache/hadoop/hdds/scm/storage/TestStreamBlockInputStream.java.

OzoneClientConfig clientConfig = conf.getObject(OzoneClientConfig.class);

// Sanity check
assertEquals(Duration.ofSeconds(5), clientConfig.getStreamReadTimeout());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To test whether OzoneClientConfig applies the new config keys correctly, add test case in existing TestOzoneClientConfig.

Comment on lines +420 to +429
// Convert Duration -> int seconds for poll(...)
final int timeoutSeconds;
if (readTimeout == null || readTimeout.isZero() || readTimeout.isNegative()) {
timeoutSeconds = 0;
} else {
long sec = readTimeout.getSeconds();
// Prevent overflow if client config is extremely large
timeoutSeconds = sec > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) sec;
}
final ReadBlockResponseProto readBlock = poll(timeoutSeconds, TimeUnit.SECONDS);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Conversion to seconds is unnecessary, since poll then converts to nanoseconds.
  • Validation should be done in OzoneClientConfig#validate()
  • Calculate timeoutNanos in StreamBlockInputStream constructor as config.getStreamReadTimeout().toNanos(). poll parameters can be removed.

Comment on lines +74 to +76
private final int responseDataSize; // Default size is 1 MB
private final long preReadSize; // Default size is 32 MB
private final Duration readTimeout; // // Default timeout is 10 second
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the comments, they easily get outdated. Default values can be checked in the config.

@Russole Russole requested a review from adoroszlai December 12, 2025 17:31
Copy link
Copy Markdown
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Russole for updating the patch. LGTM, except two minor items.

ReadBlockResponseProto poll(int timeout, TimeUnit timeoutUnit) throws IOException {
final long timeoutNanos = timeoutUnit.toNanos(timeout);
ReadBlockResponseProto poll() throws IOException {
final long timeoutNanos = readTimeoutNanos;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove timeoutNanos and use readTimeoutNanos directly.

"ozone.client.elastic.byte.buffer.pool.max.size";
public static final String OZONE_CLIENT_ELASTIC_BYTE_BUFFER_POOL_MAX_SIZE_DEFAULT = "16GB";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please avoid whiitespace-only change

Suggested change

@Russole Russole requested a review from adoroszlai December 13, 2025 01:45
Copy link
Copy Markdown
Contributor

@sreejasahithi sreejasahithi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Russole for working on this.
LGTM

@adoroszlai
Copy link
Copy Markdown
Contributor

Thanks @Russole for updating the patch. Please note that the whitespace change was made in the wrong line, so now we have 2 changed lines instead of 0. There should be no changes in hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java at all.

@Russole
Copy link
Copy Markdown
Contributor Author

Russole commented Dec 13, 2025

Thank you @adoroszlai for the reminder. I have removed all whitespace-only changes from hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java.

@adoroszlai adoroszlai requested a review from szetszwo December 13, 2025 15:55
@Russole
Copy link
Copy Markdown
Contributor Author

Russole commented Dec 13, 2025

CI failures look flaky and unrelated to this change.
Could you please re-run the failed jobs?

Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 the change looks good.

@szetszwo szetszwo merged commit 114d242 into apache:master Dec 15, 2025
82 of 84 checks passed
@szetszwo
Copy link
Copy Markdown
Contributor

@Russole , thanks for working on this!

@adoroszlai , thanks for reviewing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants